<!DOCTYPE HTML>
<html lang="en-US">
<head>
  <title>Albert - Albert 0.14.0 released</title>
  <meta charset="UTF-8">
  <link rel="icon" type="image/x-icon" href="/favicon.ico">
  <link rel="alternate" type="application/rss+xml" title="Albert RSS" href="/feed.xml">
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
  <link rel="stylesheet" href="https://albertlauncher.github.io/css/main.css">
</head>

<body>
    <main class="wrapper">
      <nav class="site-header">
    <div class="container">
        <a class="title" href="https://albertlauncher.github.io">
            <img class="icon" src="https://albertlauncher.github.io/img/albert.svg" alt="Albert" title="Albert">
            <span class="title">Albert</span>
        </a>
        <nav class="navigation float-right">
            <ul>
    <li class="">
        <a href="/">Home</a>
    </li>
    <li class="">
        <a href="/docs/">Docs</a>
    </li>
    <li class="">
        <a href="/news/">News</a>
    </li>
    <li class="">
        <a href="/help/">Help</a>
    </li>
    <li>
        <a href="https://github.com/albertlauncher/albert.git"><span class="hide-on-mobiles">View on </span>GitHub</a>
    </li>
</ul>

        </nav>
    </div>
</nav>

      <section class="container">
    <article>
        <h1>Albert 0.14.0 released</h1>
        <p>This release contains internal API changes that make developers lifes easier and and a new extension that allows to embed python scripts.</p>

<p>With this release the use of the old CGI style external extension is discouraged. External extensions will stay for now but just for personal use. As soon as the scripts in the public repo of the external extensions have been ported it will be deleted.</p>

<p>With the Python extension writing an extension can be as easy as this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">albertv0</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">__iid__</span> <span class="o">=</span> <span class="s">"PythonInterface/v0.1"</span>

<span class="k">def</span> <span class="nf">handleQuery</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">Item</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="s">"Hello"</span><span class="p">)]</span>

</code></pre></div></div>

<p>This is a valid extension. However it makes not much sense, but by adding some docs, metadata and functionality a pretty minimal example, e.g. to run Zeal, can look like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># -*- coding: utf-8 -*-
</span>
<span class="s">"""Fire up an external search in Zeal.
Just type zl &lt;query&gt;"""</span>

<span class="kn">from</span> <span class="nn">albertv0</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">run</span>
<span class="kn">from</span> <span class="nn">shutil</span> <span class="kn">import</span> <span class="n">which</span>

<span class="n">__iid__</span> <span class="o">=</span> <span class="s">"PythonInterface/v0.1"</span>
<span class="n">__prettyname__</span> <span class="o">=</span> <span class="s">"Zeal"</span>
<span class="n">__version__</span> <span class="o">=</span> <span class="s">"1.0"</span>
<span class="n">__trigger__</span> <span class="o">=</span> <span class="s">"zl "</span>
<span class="n">__author__</span> <span class="o">=</span> <span class="s">"Manuel Schneider"</span>
<span class="n">__dependencies__</span> <span class="o">=</span> <span class="p">[</span><span class="s">"zeal"</span><span class="p">]</span>


<span class="k">if</span> <span class="n">which</span><span class="p">(</span><span class="s">"zeal"</span><span class="p">)</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
    <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="s">"'zeal' is not in $PATH."</span><span class="p">)</span>


<span class="n">iconPath</span> <span class="o">=</span> <span class="n">iconLookup</span><span class="p">(</span><span class="s">'zeal'</span><span class="p">)</span>


<span class="k">def</span> <span class="nf">handleQuery</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">query</span><span class="o">.</span><span class="n">isTriggered</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[</span>
            <span class="n">Item</span><span class="p">(</span>
                <span class="nb">id</span><span class="o">=</span><span class="n">__prettyname__</span><span class="p">,</span>
                <span class="n">icon</span><span class="o">=</span><span class="n">iconPath</span><span class="p">,</span>
                <span class="n">text</span><span class="o">=</span><span class="n">__prettyname__</span><span class="p">,</span>
                <span class="n">subtext</span><span class="o">=</span><span class="s">"Look up </span><span class="si">%</span><span class="s">s"</span> <span class="o">%</span> <span class="n">__prettyname__</span><span class="p">,</span>
                <span class="n">completion</span><span class="o">=</span><span class="n">query</span><span class="o">.</span><span class="n">rawString</span><span class="p">,</span>
                <span class="n">actions</span><span class="o">=</span><span class="p">[</span><span class="n">ProcAction</span><span class="p">(</span><span class="s">"Start query in </span><span class="si">%</span><span class="s">s"</span> <span class="o">%</span> <span class="n">__prettyname__</span><span class="p">,</span>
                                    <span class="p">[</span><span class="s">"zeal"</span><span class="p">,</span> <span class="n">query</span><span class="o">.</span><span class="n">string</span><span class="p">])])</span>
        <span class="p">]</span>
</code></pre></div></div>

<p>This 26 lines build a full fledged extension. In fact it is the Zeal extension.</p>

<p>The documentation is not written at the moment, but the API is darn easy. Take a look at the <a href="https://github.com/albertlauncher/python/blob/master/api_test/__init__.py">API test extension</a>. It should contain every possible thing you can use. If you want to know it exactly read the <a href="https://github.com/albertlauncher/plugins/blob/master/python/src/extension.cpp#L60">interface definition</a>. For real examples of extensions check the <a href="https://github.com/albertlauncher/python/">extensions shipped with albert</a>.</p>

<p>I ask the devs of the external extensions in the public repo to port their extensions to the new scripting API and send a pull request.</p>

<p>I hope you enjoy the new scripting API and I’d be happy to receive pull requests for extensions you wish to see shipped with albert. Have fun.</p>

<p>As always check the <a href="https://github.com/albertlauncher/albert/commits/v0.14.0">git log</a> for details.</p>

    </article>
</section>

      
      <script>
  var anchorForId = function (id) {
    var anchor = document.createElement("a");
    anchor.className = "header-link";
    anchor.href      = "#" + id;
    anchor.innerHTML = "<i class=\"fa fa-link\"></i>";
    anchor.title = "Permalink";
    return anchor;
  };

  var linkifyAnchors = function (level, containingElement) {
    var headers = containingElement.getElementsByTagName("h" + level);
    for (var h = 0; h < headers.length; h++) {
      var header = headers[h];

      if (typeof header.id !== "undefined" && header.id !== "") {
        header.appendChild(anchorForId(header.id));
      }
    }
  };

  document.onreadystatechange = function () {
    if (this.readyState === "complete") {
      var contentBlock = document.getElementsByClassName("docs")[0] || document.getElementsByClassName("news")[0];
      if (!contentBlock) {
        return;
      }
      for (var level = 1; level <= 6; level++) {
        linkifyAnchors(level, contentBlock);
      }
    }
  };

  var topEdge
  document.onscroll = function () {
    if (topEdge === undefined)
      topEdge = document.getElementById("doc_nav").getBoundingClientRect().top+window.pageYOffset-20;

    if ( window.pageYOffset > topEdge)
      document.getElementById("doc_nav").classList.add("stuck");
    else
      document.getElementById("doc_nav").classList.remove("stuck");
  };



</script>

    </main>
</body>
</html>
